﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

using System.CodeDom;
using System.CodeDom.Compiler;

using EdgeStatz.ESSystems.Objects;

namespace EdgeStatz.ModelEngine.FormTools
{
    public class FormEngine
    {
        FormToolsXml xmlFtObj;
        AppDomain genforms;

        string xmlPath;
        System.Reflection.Assembly compiledAssembly;
        public string ModelName
        { get { return xmlFtObj.ModelName; } }
        public string ModelPath
        { get { return xmlFtObj.ModelPath; } }
        
        public FormEngine(string xmlPath)
        {
            SetXMLPath(xmlPath);
            GlobalObjectsSQL.SetConnectionString();
        }
        
        public void SetXMLPath(string xmlPath)
        {
            this.xmlPath = xmlPath;
            xmlFtObj = new FormToolsXml(xmlPath);
        }

        public FormDefinition[] FormDefinitions
        {
            get { return xmlFtObj.FormDefinitions; }
            set { xmlFtObj.FormDefinitions = value; }
        }

        public void SetFormDefinitions() { }

        public void ReplaceFormDefinitionByFolderName(FormDefinition value, string name)
        {
            xmlFtObj.ReplaceFormDefinitionByFolderName(value, name);
        }

        public void AddFormDefinition(FormDefinition value) 
        {
            xmlFtObj.AddFormDefinition(value);
        }
        public FormDefinition GetDefinitionByFolderName(string name)
        {
            foreach (FormDefinition fdef in FormDefinitions)
            {
                if (fdef.Folder.Trim().ToLower().Equals(name.Trim().ToLower()))
                    return fdef;
            }
            return null;
        }

        public void SaveModelFile() { xmlFtObj.SaveFile(); }

        #region Load Assembly/Control

        public UserControl LoadControl(string typeName)
        {
            if (compiledAssembly == null)
                throw new NullReferenceException("No Assemblies have been compiled");
            return LoadControl(compiledAssembly.GetType("EdgeStatz.GeneratedForms." + typeName));
        }

        public UserControl LoadControl(string typeName, object[] data)
        {
            if (compiledAssembly == null)
                throw new NullReferenceException("No Assemblies have been compiled");
            return LoadControl(compiledAssembly.GetType("EdgeStatz.GeneratedForms." + typeName), data);
        }

        public UserControl LoadControl(Type controlType)
        {
            if (compiledAssembly == null)
                throw new NullReferenceException("No Assemblies have been compiled");
            return Activator.CreateInstance(controlType) as UserControl;
        }

        public UserControl LoadControl(Type controlType, object[] data)
        {
            if (compiledAssembly == null)
                throw new NullReferenceException("No Assemblies have been compiled");
            return Activator.CreateInstance(controlType,data) as UserControl;
        }

        public void CompileNewAssembly()
        {
            CompileFormFile();
        }

        public void LoadExistingAssembly()
        {
            if (xmlFtObj.AssemblyName == null)
                throw new Exception("AssemblyName not found");
            List<System.Reflection.Assembly> currentassemblies = new List<System.Reflection.Assembly>{};
            currentassemblies.AddRange(AppDomain.CurrentDomain.GetAssemblies());
            foreach(System.Reflection.Assembly asm in currentassemblies)
            {
                if (asm.ManifestModule.Name == xmlFtObj.AssemblyName)
                    compiledAssembly = asm;
            }
            if(compiledAssembly == null)
                compiledAssembly = System.Reflection.Assembly.LoadFile(xmlFtObj.ModelPath + xmlFtObj.AssemblyName);
        }

        #endregion

        #region File Compile
        private void CompileFormFile() 
        {
            List<string> files = new List<string> { };
            List<string> cpars = new List<string> { };
            List<string> rex = new List<string> { };
            foreach (FormDefinition fdef in xmlFtObj.FormDefinitions)
            {
                if (fdef.FilePath != null && fdef.FilePath != "")
                {
                    foreach (string resource in fdef.Resources)
                    {
                        if (!rex.Contains(resource))
                        {
                            rex.Add(resource);
                        }
                    }
                    files.Add(fdef.FilePath);
                    foreach(string cstr in fdef.CompileParameters)
                    {
                        if (!cpars.Contains(cstr))
                            cpars.Add(cstr);
                    }

                }
            }
            CodeDomProvider provider = new Microsoft.CSharp.CSharpCodeProvider();
            
            CompilerParameters cp = new CompilerParameters(cpars.ToArray());
            cp.GenerateInMemory = false;
            cp.OutputAssembly = xmlFtObj.ModelPath + "EdgeStatz.GeneratedForms." + xmlFtObj.ModelName + ".dll";
            cp.TempFiles.KeepFiles = false;
            cp.TreatWarningsAsErrors = true;
            cp.IncludeDebugInformation = true;
            foreach (string res in rex.ToArray())
            {
                cp.EmbeddedResources.Add(res);
            }
            
            CompilerResults results = provider.CompileAssemblyFromFile(cp, files.ToArray());
            if (results.Errors.HasErrors)
            {
                string errors = "";
                foreach (CompilerError err in results.Errors)
                    errors += "File: " + err.FileName + "; Line (" + err.Line + ") - " + err.ErrorText + "\n";
                MessageBox.Show(errors);
                return;
            }
            compiledAssembly = results.CompiledAssembly;
            xmlFtObj.AssemblyName = "EdgeStatz.GeneratedForms." + xmlFtObj.ModelName + ".dll";
            //SetAllFormsAsCompiled();
        }

        public void SetAllFormsAsCompiled()
        {
            List<FormDefinition> forms = new List<FormDefinition> { };
            foreach (FormDefinition fd in xmlFtObj.FormDefinitions)
            {
                forms.Add(new FormDefinition(fd.Name, fd.Folder));
            }
            xmlFtObj.FormDefinitions = forms.ToArray();
            xmlFtObj.SaveFile();
        }
        #endregion
    }
}